/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as fs from 'fs';
import * as path from 'path';
import { compressTikToken } from './build/compressTikToken';
import { copyStaticAssets } from './build/copyStaticAssets';

export interface ITreeSitterGrammar {
	name: string;
	/**
	 * A custom .wasm filename if the grammar node module doesn't follow the standard naming convention
	 */
	filename?: string;
	/**
	 * The path where we should spawn `tree-sitter build-wasm`
	 */
	projectPath?: string;
}

const treeSitterGrammars: ITreeSitterGrammar[] = [
	{
		name: 'tree-sitter-c-sharp',
		filename: 'tree-sitter-c_sharp.wasm' // non-standard filename
	},
	{
		name: 'tree-sitter-cpp',
	},
	{
		name: 'tree-sitter-go',
	},
	{
		name: 'tree-sitter-javascript', // Also includes jsx support
	},
	{
		name: 'tree-sitter-python',
	},
	{
		name: 'tree-sitter-ruby',
	},
	{
		name: 'tree-sitter-typescript',
		projectPath: 'tree-sitter-typescript/typescript', // non-standard path
	},
	{
		name: 'tree-sitter-tsx',
		projectPath: 'tree-sitter-typescript/tsx', // non-standard path
	},
	{
		name: 'tree-sitter-java',
	},
	{
		name: 'tree-sitter-rust',
	},
	{
		name: 'tree-sitter-php'
	}
];

const REPO_ROOT = path.join(__dirname, '..');

/**
 * @github/copilot depends on sharp which has native dependencies that are hard to distribute.
 * This function creates a shim for the sharp module that @github/copilot expects.
 * The shim provides a minimal implementation of the sharp API to satisfy @github/copilot's requirements.
 * Its non-functional and only intended to make the module load without errors.
 *
 * We create a directory @github/copilot/node_modules/sharp, so that
 * the node module resolution algorithm finds our shim instead of trying to load the real sharp module. This also ensure the shims are specific to this package.
 */
async function createCopilotCliSharpShim() {
	const copilotCli = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot');
	const sharpShim = path.join(copilotCli, 'node_modules', 'sharp');

	const copilotPackageJsonFile = path.join(copilotCli, 'package.json');
	const copilotPackageJson = JSON.parse(fs.readFileSync(copilotPackageJsonFile, 'utf-8'));
	if (copilotPackageJson.dependencies) {
		delete copilotPackageJson.dependencies.sharp;
	}

	await fs.promises.writeFile(copilotPackageJsonFile, JSON.stringify(copilotPackageJson, undefined, 2), 'utf-8');
	await fs.promises.rm(sharpShim, { recursive: true, force: true });
	await fs.promises.mkdir(path.join(sharpShim, 'lib'), { recursive: true });
	await fs.promises.writeFile(path.join(sharpShim, 'package.json'), JSON.stringify({
		"name": "sharp",
		"type": "commonjs",
		"main": "lib/index.js"
	}, undefined, 2));
	await fs.promises.writeFile(path.join(sharpShim, 'lib', 'index.js'), `
const Sharp = function (inputBuffer, options) {
	if (arguments.length === 1 && !is.defined(input)) {
		throw new Error('Invalid input');
	}
	if (!(this instanceof Sharp)) {
		return new Sharp(input, options);
	}
	this.inputBuffer = inputBuffer;
	return this;
};

Sharp.prototype.resize = function () {
	const that = this;
	const img = {
		toBuffer: () => that.inputBuffer,
		png: () => img,
		jpeg: () => img
	};
	return img;
};

module.exports = Sharp;
`);

}

async function main() {
	await fs.promises.mkdir(path.join(REPO_ROOT, '.build'), { recursive: true });

	const vendoredTiktokenFiles = ['src/platform/tokenizer/node/cl100k_base.tiktoken', 'src/platform/tokenizer/node/o200k_base.tiktoken'];

	for (const tokens of vendoredTiktokenFiles) {
		await compressTikToken(tokens, `dist/${path.basename(tokens)}`);
	}

	// copy static assets to dist
	await copyStaticAssets([
		...treeSitterGrammars.map(grammar => `node_modules/@vscode/tree-sitter-wasm/wasm/${grammar.name}.wasm`),
		'node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter.wasm',
	], 'dist');

	await createCopilotCliSharpShim();

	// Check if the base cache file exists
	const baseCachePath = path.join('test', 'simulation', 'cache', 'base.sqlite');
	if (!fs.existsSync(baseCachePath)) {
		throw new Error(`Base cache file does not exist at ${baseCachePath}. Please ensure that you have git lfs installed and initialized before the repository is cloned.`);
	}

	await copyStaticAssets([
		`node_modules/@anthropic-ai/claude-code/cli.js`,
		`node_modules/@anthropic-ai/claude-code/yoga.wasm`,
		// `node_modules/@anthropic-ai/claude-code/vendor/ripgrep/${process.arch}-${process.platform}/ripgrep`,
	], 'dist');
}

main();
